class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  move(distance: number = 0) {
    console.log(`move meters ${distance}s`);
  }
}

class Snake extends Animal {
  constructor(name: string) {
    super(name);
  }
  move(distance: number = 5) {
    console.log(`move meters ${distance}s`);
  }
}

class Horse extends Animal {
  constructor(name: string) {
    super(name);
  }
}

// 继承类也可被称为派生类
// 派生类访问this之前一定要先调用super()

let ss = new Snake('ss');
let hh = new Horse('ss');

ss.move();
hh.move();

// public

// private

// protected

// readonly

// 参数属性

// 存取器
// 首先，存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到
// ECMAScript 3。 其次，只带有 get 不带有 set 的存取器自动被推断
// 为 readonly 。 这在从代码生成 .d.ts 文件时是有帮助的，因为利用这个属性的
// 用户会看到不允许够改变它的值。
let passcode = 'secret passcode';
class Employee {
  private _fullName: string;
  get fullName(): string {
    return this._fullName;
  }
  set fullName(newName: string) {
    if (passcode && passcode == 'secret passcode') {
      this._fullName = newName;
    } else {
      console.log('Error: Unauthorized update of employee!');
    }
  }
}

// 静态属性
class Grid {
  static origin = { x: 0, y: 0 };
  calculateDistanceFromOrigin(point: { x: number; y: number }) {
    let xDist = point.x - Grid.origin.x;
    let yDist = point.y - Grid.origin.y;
    return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
  }
  constructor(public scale: number) {}
}
let grid1 = new Grid(1.0); // 1x scale
let grid2 = new Grid(5.0); // 5x scale
console.log(grid1.calculateDistanceFromOrigin({ x: 10, y: 10 }));
console.log(grid2.calculateDistanceFromOrigin({ x: 10, y: 10 }));

// 抽象类
abstract class AbstractAnimal {
  abstract makeSound(): void;
  move(): void {
    console.log('roaming the earth...');
  }
}
// 抽象类的实例
abstract class Department {
  constructor(public name: string) {}
  printName(): void {
    console.log('Department name: ' + this.name);
  }
  // 必须在派生类中实现
  abstract printMeeting(): void;
}

class AccountingDepartment extends Department {
  constructor() {
    super('Accounting and Auditing');
    // 在派生类的构造函数中必须调用 super()
  }
  printMeeting(): void {
    console.log('The Accounting Department meets each Monday  at 10am.');
  }
  generateReports(): void {
    console.log('Generating accounting reports...');
  }
}
// 允许创建一个对抽象类型的引用
let department: Department;
// 错误: 不能创建一个抽象类的实例
// department = new Department();
department = new AccountingDepartment(); // 允许对一个抽象子类进行实
// 例化和赋值
department.printName();
department.printMeeting();
// 错误: 方法在声明的抽象类中不存在
// department.generateReports();

// 构造函数

// 把类当做接口使用
